package com.niiwoo.civet.user.service.duboo;

import com.alibaba.dubbo.config.annotation.Service;
import com.niiwoo.civet.user.constants.LoginAccountErrorCode;
import com.niiwoo.civet.user.dao.entity.DataStatus;
import com.niiwoo.civet.user.dao.entity.IdentityInfo;
import com.niiwoo.civet.user.dao.entity.IdentityMapping;
import com.niiwoo.civet.user.dao.entity.UserImageFile;
import com.niiwoo.civet.user.dto.request.OCRAuthInfoRequestDTO;
import com.niiwoo.civet.user.dto.request.OCRImageItemDTO;
import com.niiwoo.civet.user.dto.request.OCRNotAuthInfoRequestDTO;
import com.niiwoo.civet.user.dto.request.OCRStatusInfoRequestDTO;
import com.niiwoo.civet.user.dto.response.OCRStatusInfoResponseDTO;
import com.niiwoo.civet.user.dto.response.UserIdentityInfoResponseDTO;
import com.niiwoo.civet.user.dto.response.UserPortraitParamDTO;
import com.niiwoo.civet.user.enums.*;
import com.niiwoo.civet.user.service.UserForbidDubboService;
import com.niiwoo.civet.user.service.UserIdentityDubboService;
import com.niiwoo.civet.user.service.local.IdentityMappingService;
import com.niiwoo.civet.user.service.local.UserIdentityService;
import com.niiwoo.civet.user.service.local.UserImageFileService;
import com.niiwoo.civet.user.service.local.UserStatusService;
import com.niiwoo.tripod.base.component.PrivacyMasks;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;

/**
 * 用户身份信息API实现
 */
@Service(version = "1.0.0")
public class UserIdentityDubboServiceImpl implements UserIdentityDubboService {

    @Autowired
    UserIdentityService userIdentityLocalService;

    @Autowired
    UserStatusService userStatusService;

    @Autowired
    PrivacyMasks privacyMasks;

    @Autowired
    UserImageFileService userImageFileService;

    @Autowired
    SnowflakeIdWorker snowflakeIdWorker;

    @Autowired
    IdentityMappingService identityMappingService;

    @Autowired
    UserForbidDubboService userForbidDubboService;

    /**
     * 获取用户身份信息
     *
     * @param userId 用户id
     */
    @Override
    public UserIdentityInfoResponseDTO get(String userId) {
        return Optional.ofNullable(userIdentityLocalService.getByUserId(userId)).map(info -> {
            UserIdentityInfoResponseDTO dto = new UserIdentityInfoResponseDTO();
            BeanUtils.copyProperties(info,dto);
            dto.setName(info.getName());
            dto.setIdCard(decryptIdCard(info.getIdCard()));
            dto.setEndDate(info.getEndDate());
            return dto;
        }).orElse(null);
    }

    public List<UserIdentityInfoResponseDTO> queryUserIdentityListByUserIdSet(Set<String> userIdSet) {
        return userIdentityLocalService.queryUserIdentityListByUserIdSet(userIdSet);
    }

    /**
     * 获取OCR相关状态(状态、身份信息、图片)
     */
    @Override
    public OCRStatusInfoResponseDTO getIdentityAndStatusAndImage(OCRStatusInfoRequestDTO requestDTO) {
        OCRStatusInfoResponseDTO responseDTO = new OCRStatusInfoResponseDTO();
        // 查询状态
        List<DataStatus> statusList = Optional.ofNullable(userStatusService.getDataStatusByUserId(requestDTO.getUserId())).orElse(Collections.EMPTY_LIST);
        // 二要素
        responseDTO.setRealNameAuthStatus(
                statusList.stream().filter(s -> Objects.equals(s.getDataType(), UserDataTypeEnum.TWO_ELEMENT.getValue())).findFirst()
                        .map(s -> UserDataStatusEnum.RealNameAuthStatus.of(s.getDataStatus()))
                        .orElse(UserDataStatusEnum.RealNameAuthStatus.NOT_CERTIFIED)
        );
        // 肖像认证
        responseDTO.setPortraitAuthStatus(
                statusList.stream().filter(s -> Objects.equals(s.getDataType(), UserDataTypeEnum.PORTRAIT.getValue())).findFirst()
                        .map(s -> UserDataStatusEnum.PortraitAuthStatus.of(s.getDataStatus()))
                        .orElse(UserDataStatusEnum.PortraitAuthStatus.NOT_CERTIFIED)
        );
        // OCR
        responseDTO.setOcrStatus(
                statusList.stream().filter(s -> Objects.equals(s.getDataType(), UserDataTypeEnum.OCR.getValue())).findFirst()
                        .map(s -> UserDataStatusEnum.OCRStatus.of(s.getDataStatus()))
                        .orElse(UserDataStatusEnum.OCRStatus.NOT_OCR)
        );
        // 查询个人信息
        Optional.ofNullable(userIdentityLocalService.getByUserId(requestDTO.getUserId()))
                .ifPresent(info -> {
                    responseDTO.setName(info.getName());
                    responseDTO.setIdCard(decryptIdCard(info.getIdCard()));
                    responseDTO.setSex(UserIdentitySexEnum.of(info.getSex()));
                    responseDTO.setNation(info.getNation());
                    responseDTO.setBirthday(info.getBirthday());
                    responseDTO.setEndDate(info.getEndDate());
                    responseDTO.setStartDate(info.getStartDate());
                    responseDTO.setAddress(info.getAddress());
                    responseDTO.setSigningAuthority(info.getSigningAuthority());
                    responseDTO.setLastOCRChannel(info.getOcrChannel() != null ? OCRChannelEnum.of(info.getOcrChannel()) : OCRChannelEnum.EMPTY);
                    if (info.getEndDate() != null) {
                        responseDTO.setIdCardExpiredStatus(UserDataStatusEnum.IdCardExpiredStatus.get(info.getEndDate(), 30));
                    }
                });
        if (responseDTO.getLastOCRChannel() == null) {
            responseDTO.setLastOCRChannel(OCRChannelEnum.EMPTY);
        }
        // 身份证图片信息
        List<UserImageFile> userImageList = Optional.ofNullable(userImageFileService.getListByType(requestDTO.getUserId(), UserImgTypeEnum.IDCARD_IMAGE)).orElse(Collections.EMPTY_LIST);
        // 正面照
        userImageList.stream()
                .filter(d -> Objects.equals(d.getSubType(), UserImgTypeEnum.IDCARD_FRONT_IMAGE.getValue()))
                .findFirst()
                .ifPresent(userImageFile -> {
                    responseDTO.setFrontPhotoUrl(userImageFile.getImgUrl());
                    responseDTO.setFrontPhotoId(userImageFile.getId());
                });
        // 反面照
        userImageList.stream()
                .filter(d -> Objects.equals(d.getSubType(), UserImgTypeEnum.IDCARD_BACK_IMAGE.getValue()))
                .findFirst()
                .ifPresent(userImageFile -> {
                    responseDTO.setBackPhotoUrl(userImageFile.getImgUrl());
                    responseDTO.setBackPhotoId(userImageFile.getId());
                });
        // 手持照
        userImageList.stream()
                .filter(d -> Objects.equals(d.getSubType(), UserImgTypeEnum.IDCARD_HAND_IMAGE.getValue()))
                .findFirst()
                .ifPresent(userImageFile -> {
                    responseDTO.setHandPhotoUrl(userImageFile.getImgUrl());
                    responseDTO.setHandPhotoId(userImageFile.getId());
                });

        boolean isForbid = Optional.ofNullable(userForbidDubboService.queryValidUserForbidInfo(requestDTO.getUserId(), UserForbidTypeEnum.IDENTITY)).isPresent();
        responseDTO.setIsForbidIdentityAuth(isForbid);
        return responseDTO;
    }


    /**
     * 保存OCR认证信息, OCR状态更新为通过
     */
    @Override
    public boolean saveAuthInfo(OCRAuthInfoRequestDTO requestDTO) {
        assertPermitIdentityAuth(requestDTO.getUserId());
        // 查询状态
        List<DataStatus> statusList = Optional.ofNullable(userStatusService.getDataStatusByUserId(requestDTO.getUserId())).orElse(Collections.emptyList());
        // 二要素
        boolean isTwoElementAuth = statusList.stream()
                .filter(s -> Objects.equals(s.getDataType(), UserDataTypeEnum.TWO_ELEMENT.getValue())).findFirst()
                .map(s -> UserDataStatusEnum.RealNameAuthStatus.of(s.getDataStatus()) == UserDataStatusEnum.RealNameAuthStatus.PASS_CERTIFIED)
                .orElse(false);
        // 肖像认证
        boolean isPortraitAuth = statusList.stream()
                .filter(s -> Objects.equals(s.getDataType(), UserDataTypeEnum.PORTRAIT.getValue())).findFirst()
                .map(s -> UserDataStatusEnum.PortraitAuthStatus.of(s.getDataStatus()) == UserDataStatusEnum.PortraitAuthStatus.PASS_CERTIFIED)
                .orElse(false);
        // OCR
        boolean isOCR = statusList.stream()
                .filter(s -> Objects.equals(s.getDataType(), UserDataTypeEnum.OCR.getValue())).findFirst()
                .map(s -> UserDataStatusEnum.OCRStatus.of(s.getDataStatus()) == UserDataStatusEnum.OCRStatus.YES_OCR)
                .orElse(false);
        Optional<IdentityInfo> identityInfoOpt = Optional.ofNullable(userIdentityLocalService.getByUserId(requestDTO.getUserId()));
        // String ecryptIdCard = ecryptIdCard(requestDTO.getIdCard());
        String idCard = requestDTO.getIdCard();
        String ecryptIdCardUpper = privacyMasks.encryptPrivacy(idCard.toUpperCase());
        String ecryptIdCardLower = privacyMasks.encryptPrivacy(idCard.toLowerCase());
        // 如果已通过二要素认证， 则
        if (isTwoElementAuth) {
            IdentityInfo oldInfo = identityInfoOpt.orElseThrow(() -> new BizException(LoginAccountErrorCode.IDENTIFY_INFO_NOT_FOUND));
            // 校验姓名和身份账号是否一致
            if (!oldInfo.getName().equals(requestDTO.getName()) || !oldInfo.getIdCard().equalsIgnoreCase(ecryptIdCardUpper)) {
                throw new BizException(LoginAccountErrorCode.OCR_TWO_ELEMENT_NOT_MATCH);
            }
            // 已 OCR 和通过肖像认证，除非身份证信息快过期或已过期，否则不能修改
            if (isOCR && isPortraitAuth && UserDataStatusEnum.IdCardExpiredStatus.isValid(oldInfo.getEndDate(), 30)) {
                throw new BizException(LoginAccountErrorCode.ID_CARD_IS_STILL_VALID);
            }
        }
        // 身份是否被使用
        Optional<IdentityMapping> mappingOptional1 = Optional.ofNullable(identityMappingService.get(ecryptIdCardUpper));
        if (mappingOptional1.isPresent() && !mappingOptional1.get().getUserId().equals(requestDTO.getUserId())) {
            throw new BizException(LoginAccountErrorCode.ID_CARD_HAS_BEEN_CERTIFIED);
        }
        Optional<IdentityMapping> mappingOptional2 = Optional.ofNullable(identityMappingService.get(ecryptIdCardLower));
        if (mappingOptional2.isPresent() && !mappingOptional2.get().getUserId().equals(requestDTO.getUserId())) {
            throw  new BizException(LoginAccountErrorCode.ID_CARD_HAS_BEEN_CERTIFIED);
        }
        // 身份信息
        IdentityInfo info = new IdentityInfo();
        // 二要素通过后，姓名和身份证号不修改
        if (!isTwoElementAuth) {
            info.setName(requestDTO.getName());
            info.setIdCard(ecryptIdCardUpper);
            info.setSex(requestDTO.getSex().getValue());
        }
        info.setAddressCode(requestDTO.getAddressCode());
        info.setUserId(requestDTO.getUserId());
        info.setNation(requestDTO.getNation());
        info.setStartDate(requestDTO.getStartDate());
        info.setEndDate(requestDTO.getEndDate());
        info.setAddress(requestDTO.getAddress());
        info.setSigningAuthority(requestDTO.getSigningAuthority());
        info.setOcrChannel(requestDTO.getOcrChannel().getValue());
        info.setCreateTime(new Date());
        info.setBirthday(requestDTO.getBirthday());
        // 正面照
        UserImageFile frontImage = generateIdICardmageFile(requestDTO.getUserId(), UserImgTypeEnum.IDCARD_IMAGE, UserImgTypeEnum.IDCARD_FRONT_IMAGE, requestDTO.getFrontImage());
        // 反面照
        UserImageFile backImage = generateIdICardmageFile(requestDTO.getUserId(), UserImgTypeEnum.IDCARD_IMAGE, UserImgTypeEnum.IDCARD_BACK_IMAGE, requestDTO.getBackImage());

        // 手持照片
        UserImageFile handImage = null;
        if(requestDTO.getHandImage() != null){
            handImage = generateIdICardmageFile(requestDTO.getUserId(), UserImgTypeEnum.IDCARD_IMAGE, UserImgTypeEnum.IDCARD_HAND_IMAGE, requestDTO.getHandImage());
        }

        // OCR更新记录
        Optional<DataStatus> oldDataStatusOpt = Optional.ofNullable(userStatusService.getByUserIdAndType(requestDTO.getUserId(), UserDataTypeEnum.OCR));
        DataStatus dataStatus = generateOCRAuthRecord(oldDataStatusOpt, requestDTO.getUserId(), UserDataStatusEnum.OCRStatus.YES_OCR);
        return userIdentityLocalService.updateAuthInfo(info, oldDataStatusOpt.isPresent(), dataStatus, frontImage, backImage,handImage);
    }

    /**
     * 保存OCR未认证信息
     */
    @Override
    public boolean focusSaveAuthInfo(OCRNotAuthInfoRequestDTO requestDTO) {
        assertPermitIdentityAuth(requestDTO.getUserId());
        // 查询状态
        List<DataStatus> statusList = Optional.ofNullable(userStatusService.getDataStatusByUserId(requestDTO.getUserId())).orElse(Collections.emptyList());
        // 二要素
        boolean isTwoElementAuth = statusList.stream()
                .filter(s -> Objects.equals(s.getDataType(), UserDataTypeEnum.TWO_ELEMENT.getValue())).findFirst()
                .map(s -> UserDataStatusEnum.RealNameAuthStatus.of(s.getDataStatus()) == UserDataStatusEnum.RealNameAuthStatus.PASS_CERTIFIED)
                .orElse(false);
        // 肖像认证
        boolean isPortraitAuth = statusList.stream()
                .filter(s -> Objects.equals(s.getDataType(), UserDataTypeEnum.PORTRAIT.getValue())).findFirst()
                .map(s -> UserDataStatusEnum.PortraitAuthStatus.except(s.getDataStatus(), UserDataStatusEnum.PortraitAuthStatus.PASS_CERTIFIED, UserDataStatusEnum.PortraitAuthStatus.NEED_APPROVE))
                .orElse(false);
        // OCR
        boolean isOCR = statusList.stream()
                .filter(s -> Objects.equals(s.getDataType(), UserDataTypeEnum.OCR.getValue())).findFirst()
                .map(s -> UserDataStatusEnum.OCRStatus.of(s.getDataStatus()) == UserDataStatusEnum.OCRStatus.YES_OCR)
                .orElse(false);
        // 将要更新的ocr状态
        UserDataStatusEnum.OCRStatus updateOcrStatus = null;
        // case 1: 已OCR, 通过肖像认证，二要素已认证
        if (isOCR && isPortraitAuth && isTwoElementAuth) {
            // 如果身份信息有效, 返回错误, 快过期和已过期则允许修改
            IdentityInfo info = userIdentityLocalService.getByUserId(requestDTO.getUserId());
            if (UserDataStatusEnum.IdCardExpiredStatus.isValid(info.getEndDate(), 30)) {
                throw new BizException(LoginAccountErrorCode.OCR_AVAILABLE);
            } else {
                updateOcrStatus = UserDataStatusEnum.OCRStatus.YES_OCR;
            }
        }
        // case 2: 已OCR, 未通过肖像认证，二要素已认证
        if (isOCR && !isPortraitAuth && isTwoElementAuth) {
            // 身份证正反面照不能修改, 必须传原照片id
            if (requestDTO.getFrontImage().getImageId() == null) {
                throw new BizException(LoginAccountErrorCode.MISS_ID_CARD_FRONT_IMAGE);
            }
            if (requestDTO.getBackImage().getImageId() == null) {
                throw new BizException(LoginAccountErrorCode.MISS_ID_CARD_BACK_IMAGE);
            }
            updateOcrStatus = UserDataStatusEnum.OCRStatus.YES_OCR;
        }
        // case 3: 已OCR, 未通过肖像认证，二要素未认证
        if (isOCR && !isPortraitAuth && !isTwoElementAuth) {
            // 身份证正反面照可以修改, 传原照片id或base64字符串
            updateOcrStatus = UserDataStatusEnum.OCRStatus.NOT_OCR;
        }
        // case 4: 未OCR, 未通过肖像认证，二要素已认证
        if (!isOCR && !isPortraitAuth && isTwoElementAuth) {
            // 身份证正反面照可以修改, 传原照片id或base64字符串
            updateOcrStatus = UserDataStatusEnum.OCRStatus.NOT_OCR;
        }
        // case 5: 未OCR, 未通过肖像认证，二要素未认证
        if (!isOCR && !isPortraitAuth && !isTwoElementAuth) {
            // 身份证正反面照可以修改, 传原照片id或base64字符串
            updateOcrStatus = UserDataStatusEnum.OCRStatus.NOT_OCR;
        }
        // case 6: 未OCR, 已通过肖像认证，二要素已认证
        if (!isOCR && isPortraitAuth && isTwoElementAuth) {
            // 身份证正反面照可以修改, 传原照片id或base64字符串
            updateOcrStatus = UserDataStatusEnum.OCRStatus.NOT_OCR;
        }
        // 正面照
        UserImageFile frontImage = generateIdICardmageFile(requestDTO.getUserId(), UserImgTypeEnum.IDCARD_IMAGE, UserImgTypeEnum.IDCARD_FRONT_IMAGE, requestDTO.getFrontImage());
        // 反面照
        UserImageFile backImage = generateIdICardmageFile(requestDTO.getUserId(), UserImgTypeEnum.IDCARD_IMAGE, UserImgTypeEnum.IDCARD_BACK_IMAGE, requestDTO.getBackImage());
        // 手持照片
        UserImageFile handImage = generateIdICardmageFile(requestDTO.getUserId(), UserImgTypeEnum.IDCARD_IMAGE, UserImgTypeEnum.IDCARD_HAND_IMAGE, requestDTO.getHandImage());
        // OCR更新记录
        Optional<DataStatus> oldDataStatusOpt = Optional.ofNullable(userStatusService.getByUserIdAndType(requestDTO.getUserId(), UserDataTypeEnum.OCR));
        DataStatus dataStatus = generateOCRAuthRecord(oldDataStatusOpt, requestDTO.getUserId(), updateOcrStatus);
        Optional<IdentityInfo> IdentityInfoOpt = Optional.ofNullable(userIdentityLocalService.getByUserId(requestDTO.getUserId()));
        return userIdentityLocalService.updateNotAuthInfo(IdentityInfoOpt, oldDataStatusOpt.isPresent(), dataStatus, frontImage, backImage, handImage);
    }

    @Override
    public boolean hasOtherIdentityMapping(String userId, String idCardNo) {
        boolean b1 = Optional.ofNullable(userIdentityLocalService.getMapping(ecryptIdCard(idCardNo.toUpperCase())))
                .map(m -> !m.getUserId().equals(userId))
                .orElse(false);
        boolean b2 = Optional.ofNullable(userIdentityLocalService.getMapping(ecryptIdCard(idCardNo.toLowerCase())))
                .map(m -> !m.getUserId().equals(userId))
                .orElse(false);
        return b1 || b2;
    }

    /**
     * 确认用户允许身份认证
     * @param userId
     */
    private void assertPermitIdentityAuth(String userId) {
        if (userForbidDubboService.queryValidUserForbidInfo(userId, UserForbidTypeEnum.IDENTITY) != null) {
            throw new BizException(LoginAccountErrorCode.IDENTITY_AUTH_FORBID);
        }
    }

    /**
     * 获取OCR更新记录
     *
     * @param oldDataStatusOpt OCR认证状态老记录
     * @param userId 用户id
     * @param status 认证状态
     */
    private DataStatus generateOCRAuthRecord(Optional<DataStatus> oldDataStatusOpt, String userId, UserDataStatusEnum.OCRStatus status) {
        DataStatus dataStatus = new DataStatus();
        if (oldDataStatusOpt.isPresent()) {
            dataStatus.setId(oldDataStatusOpt.get().getId());
            dataStatus.setUserId(userId);
        } else {
            dataStatus.setId(snowflakeIdWorker.nextId());
            dataStatus.setUserId(userId);
            dataStatus.setDataType(UserDataTypeEnum.OCR.getValue());
            dataStatus.setCreateTime(new Date());
        }
        dataStatus.setAuthTime(new Date());
        dataStatus.setDataStatus(status.getStatus());
        return dataStatus;
    }

    /**
     * 创建图片文件记录
     *
     * @param userId 用户ID
     * @param type 类型
     * @param subType 子类型
     * @param imageItemDTO OCR图片
     */
    private UserImageFile generateIdICardmageFile(String userId, UserImgTypeEnum type, UserImgTypeEnum subType, OCRImageItemDTO imageItemDTO) {
        UserImageFile imageFile = new UserImageFile();
        imageFile.setId(snowflakeIdWorker.nextId());
        imageFile.setUserId(userId);
        imageFile.setDataType(type.getValue());
        imageFile.setSubType(subType.getValue());
        imageFile.setDelStatus(ImageFileStatusEnum.VALID.getValue());
        imageFile.setCreateTime(new Date());
        // 图片URL不为空，表示上传新的图片
        if (StringUtils.isNotBlank(imageItemDTO.getImgUrl())) {
            // 原图
            imageFile.setImgUrl(imageItemDTO.getImgUrl());
            // 原图略缩图
            imageFile.setImgReleaseUrl(imageItemDTO.getImgReleaseUrl());
            // 原图打码图
            imageFile.setImgThumbnailUrl(imageItemDTO.getImgThumbnailUrl());
            // 打码略缩图
            imageFile.setImgReleaseThumbnailUrl(imageItemDTO.getImgReleaseThumbnailUrl());
            return imageFile;
        } else {
            // 使用id查找原图片，存在则拷贝一份，不存在则抛出异常
            UserImageFile oldImageFile;
            if (imageItemDTO.getImageId() == null || (oldImageFile = userImageFileService.getByType(userId, type, subType)) == null) {
                switch (subType) {
                    case IDCARD_FRONT_IMAGE: throw new BizException(LoginAccountErrorCode.MISS_ID_CARD_FRONT_IMAGE);
                    case IDCARD_BACK_IMAGE: throw new BizException(LoginAccountErrorCode.MISS_ID_CARD_BACK_IMAGE);
                    case IDCARD_HAND_IMAGE: throw new BizException(LoginAccountErrorCode.MISS_ID_CARD_HAND_IMAGE);
                    default: throw new BizException(LoginAccountErrorCode.SAVE_OCR_IMAGE_FAIL);
                }
            }
            // 原图
            imageFile.setImgUrl(oldImageFile.getImgUrl());
            // 原图略缩图
            imageFile.setImgReleaseUrl(oldImageFile.getImgReleaseUrl());
            // 原图打码图
            imageFile.setImgThumbnailUrl(oldImageFile.getImgThumbnailUrl());
            // 打码略缩图
            imageFile.setImgReleaseThumbnailUrl(oldImageFile.getImgReleaseThumbnailUrl());
            return imageFile;
        }
    }

    /**
     * 解密身份证号码
     *
     * @param idCard 身份证号码密文
     */
    private String decryptIdCard(String idCard) {
        return privacyMasks.decryptPrivacy(idCard);
    }

    /**
     * 加密身份证号码
     *
     * @param idCard 身份证号码明文
     */
    private String ecryptIdCard(String idCard) {
        return privacyMasks.encryptPrivacy(idCard);
    }


    /**
     * 查询用户画像需要的参数
     * @param userId
     * @return
     */
    public UserPortraitParamDTO queryUserPortraitParam(String userId){
        return userIdentityLocalService.queryUserPortraitParam(userId);
    }

    /**
     * 根据身份证号码查询用户ID
     *
     * @param idCard 身份证号码
     * @return
     */
    @Override
    public String queryUserIdByIdCard(String idCard) {
        return userIdentityLocalService.queryUserIdByIdCard(privacyMasks.encryptPrivacy(idCard));
    }

    @Override
    public List<UserIdentityInfoResponseDTO> queryListByRealName(String realName) {
        List<IdentityInfo> identityInfoList=userIdentityLocalService.queryIdentityInfoListByRealName(realName);
        List<UserIdentityInfoResponseDTO> result=new ArrayList<UserIdentityInfoResponseDTO>();
        for (IdentityInfo identityInfo : identityInfoList) {
            UserIdentityInfoResponseDTO dto = new UserIdentityInfoResponseDTO();
            BeanUtils.copyProperties(identityInfo, dto);
            result.add(dto);
        }

        return result;
    }

    /**
     * 资产端同步用户OCR信息和身份证照片
     * @param requestDTO
     * @return
     */
    @Override
    public boolean assetSyncOcrInfo(OCRAuthInfoRequestDTO requestDTO){
        assertPermitIdentityAuth(requestDTO.getUserId());
        // 查询状态
        List<DataStatus> statusList = Optional.ofNullable(userStatusService.getDataStatusByUserId(requestDTO.getUserId())).orElse(Collections.emptyList());
        // 二要素
        boolean isTwoElementAuth = statusList.stream()
                .filter(s -> Objects.equals(s.getDataType(), UserDataTypeEnum.TWO_ELEMENT.getValue())).findFirst()
                .map(s -> UserDataStatusEnum.RealNameAuthStatus.of(s.getDataStatus()) == UserDataStatusEnum.RealNameAuthStatus.PASS_CERTIFIED)
                .orElse(false);
        // OCR状态
        boolean isOCR = statusList.stream()
                .filter(s -> Objects.equals(s.getDataType(), UserDataTypeEnum.OCR.getValue())).findFirst()
                .map(s -> UserDataStatusEnum.OCRStatus.of(s.getDataStatus()) == UserDataStatusEnum.OCRStatus.YES_OCR)
                .orElse(false);
        Optional<IdentityInfo> identityInfoOpt = Optional.ofNullable(userIdentityLocalService.getByUserId(requestDTO.getUserId()));
        String idCard = requestDTO.getIdCard();
        String ecryptIdCardUpper = privacyMasks.encryptPrivacy(idCard.toUpperCase());
        String ecryptIdCardLower = privacyMasks.encryptPrivacy(idCard.toLowerCase());


        // 如果已通过二要素认证， 则
        if (isTwoElementAuth) {
            IdentityInfo oldInfo = identityInfoOpt.orElseThrow(() -> new BizException(LoginAccountErrorCode.IDENTIFY_INFO_NOT_FOUND));
            // 校验姓名和身份账号是否一致
            if (!oldInfo.getName().equals(requestDTO.getName()) || !oldInfo.getIdCard().equalsIgnoreCase(ecryptIdCardUpper)) {
                throw new BizException(LoginAccountErrorCode.OCR_TWO_ELEMENT_NOT_MATCH);
            }
        }
        // 身份是否被使用
        Optional<IdentityMapping> mappingOptional1 = Optional.ofNullable(identityMappingService.get(ecryptIdCardUpper));
        if (mappingOptional1.isPresent() && !mappingOptional1.get().getUserId().equals(requestDTO.getUserId())) {
            throw new BizException(LoginAccountErrorCode.ID_CARD_HAS_BEEN_CERTIFIED);
        }
        Optional<IdentityMapping> mappingOptional2 = Optional.ofNullable(identityMappingService.get(ecryptIdCardLower));
        if (mappingOptional2.isPresent() && !mappingOptional2.get().getUserId().equals(requestDTO.getUserId())) {
            throw  new BizException(LoginAccountErrorCode.ID_CARD_HAS_BEEN_CERTIFIED);
        }
        // 身份信息
        IdentityInfo info = new IdentityInfo();
        // 二要素通过后，姓名和身份证号不修改
        if (!isTwoElementAuth) {
            info.setName(requestDTO.getName());
            info.setIdCard(ecryptIdCardUpper);
            info.setSex(requestDTO.getSex().getValue());
        }
        info.setAddressCode(requestDTO.getAddressCode());
        info.setUserId(requestDTO.getUserId());
        info.setNation(requestDTO.getNation());
        info.setStartDate(requestDTO.getStartDate());
        info.setEndDate(requestDTO.getEndDate());
        info.setAddress(requestDTO.getAddress());
        info.setSigningAuthority(requestDTO.getSigningAuthority());
        info.setOcrChannel(requestDTO.getOcrChannel().getValue());
        info.setCreateTime(new Date());
        info.setBirthday(requestDTO.getBirthday());
        // 正面照
        UserImageFile frontImage = generateIdICardmageFile(requestDTO.getUserId(), UserImgTypeEnum.IDCARD_IMAGE, UserImgTypeEnum.IDCARD_FRONT_IMAGE, requestDTO.getFrontImage());
        // 反面照
        UserImageFile backImage = generateIdICardmageFile(requestDTO.getUserId(), UserImgTypeEnum.IDCARD_IMAGE, UserImgTypeEnum.IDCARD_BACK_IMAGE, requestDTO.getBackImage());

        // 手持照片
        UserImageFile handImage = null;
        if(requestDTO.getHandImage() != null){
            handImage = generateIdICardmageFile(requestDTO.getUserId(), UserImgTypeEnum.IDCARD_IMAGE, UserImgTypeEnum.IDCARD_HAND_IMAGE, requestDTO.getHandImage());
        }

        // OCR更新记录
        Optional<DataStatus> oldDataStatusOpt = Optional.ofNullable(userStatusService.getByUserIdAndType(requestDTO.getUserId(), UserDataTypeEnum.OCR));
        DataStatus dataStatus = generateOCRAuthRecord(oldDataStatusOpt, requestDTO.getUserId(), UserDataStatusEnum.OCRStatus.YES_OCR);
        return userIdentityLocalService.updateAuthInfo(info, oldDataStatusOpt.isPresent(), dataStatus, frontImage, backImage,handImage);
    }

}
